feat: Handle attachments in compose and reply based on a neovim buffer#39
feat: Handle attachments in compose and reply based on a neovim buffer#39jugarpeupv wants to merge 27 commits intoyousefakbar:mainfrom
Conversation
Detects calendar files by MIME type or extension and attempts to render them using the external script `render-calendar-attachment.py`. If the script is not available, a message is shown with a link to download it. This improves the handling of .ics and similar calendar attachments in the default view handler.
Formatter fixed mixed indentation (tabs vs spaces) and inconsistent spacing throughout the file to match project style guidelines.
Added documentation for the new optional email address parameter in the :Inbox command, which allows filtering inbox by recipient address with autocomplete support. Updated CHANGELOG.md, README.md, and doc/notmuch.txt to reflect the new functionality.
Replace brittle regex-based text parsing with structured JSON parsing for displaying email threads. This provides more reliable MIME handling and enables new features. Changes: - Add thread.lua module with JSON-based thread processing - Replace `notmuch show | col` with `notmuch show --format=json` - Handle complex MIME structures (multipart/mixed, multipart/alternative) - Concatenate multiple inline text parts (body, signatures, footers) - Show MIME markers for attachments and HTML content New features: - Per-message tag display in thread headers - Attachment count indicator (📎) in message headers - Proper handling of text/plain attachments vs inline content Deprecates util.process_msgs_in_thread() in favor of thread.show_thread()
Add support for rendering HTML email bodies in thread view using w3m. This is useful for multipart/alternative emails where HTML content is often richer than the plain text alternative. - Add `render_html_body` config option (default: false) - Add `render_html()` function with w3m integration - Graceful fallback when w3m is not installed or fails - Fetch HTML content from notmuch with `--include-html` flag - Add module-level documentation to thread.lua
Add `vim.b.notmuch_thread` buffer variable containing thread-level metadata for extensibility (statusline integration, custom scripts). Exported fields: - id: Thread ID for notmuch queries - subject: Thread subject from root message - date_relative: Root message date - message_count: Total messages in thread - tags: Union of all message tags (sorted) - authors: Unique participants (full From header, deduplicated) Implementation: - Accumulate metadata during `build_message_lines()` tree traversal - Return (lines, metadata) tuple from `show_thread()` - Caller sets buffer variable after creating buffer This is the first of several buffer variables that will enable O(1) message lookup and rich statusline integration.
Add `vim.b.notmuch_messages` buffer variable containing an array of
message objects for cursor-to-message lookup and statusline integration.
Each message entry includes:
- id: Message-ID for notmuch queries
- start_line, end_line, fold_line: Line ranges for cursor mapping
- depth: Reply depth in thread
- from, subject, date_relative: Display fields
- tags: Per-message tags array
- attachment_count: Number of attachments
Implementation:
- Track line positions during `build_message_lines()` traversal
- Restructure metadata return as { thread, messages } object
- Caller sets both `vim.b.notmuch_thread` and `vim.b.notmuch_messages`
This enables O(m) message lookup by cursor position, replacing the
O(n) buffer-scanning approach in `util.find_cursor_msg_id()`.
Add `vim.b.notmuch_current` and `vim.b.notmuch_status` buffer variables that automatically update as the cursor moves through the thread. `vim.b.notmuch_current` contains: - All fields from the message at cursor (id, from, tags, etc.) - index: 1-based position in thread - total: total message count `vim.b.notmuch_status` contains a pre-formatted string for statusline: - Format: "2/7 Alice Smith" or "2/7 Alice Smith 📎2" with attachments Implementation: - Add get_message_at_line() for O(m) cursor-to-message lookup - Add update_current_message() to refresh buffer variables - Add setup_cursor_tracking() to create buffer-local CursorMoved autocmd - Fast path optimization skips update if cursor still in same message
Simplifies operations (8 instances) where ID was being fetching the current (cursor) message ID by scanning lines backwards. Instead, we simply reference the `id` field in the buffer-local variable `vim.b.notmuch_current`, which is updated via autocmd on every cursor move event.
…mprovements Adds detail on new thread metadata buffer variables for statusline integration and clarifies the refactored message ID lookup pattern.
Previously, show_thread() only processed json[1][1], assuming a single root node. Threads with multiple depth-0 messages (e.g., orphaned replies, merged threads) were truncated to only the first message. Now iterates over all nodes in json[1] to display the complete thread.
When cursor is at the top of the buffer or in a gap between messages, update_current_message() now falls back to finding the first message whose start_line is after the cursor position. Previously it would clear notmuch_current and notmuch_status, leaving the status bar empty despite messages being present in the thread.
- README: Add w3m as optional dependency, render_html_body config option, and new "Statusline Integration" section with lualine example - Help: Add render_html_body option, w3m dependency, comprehensive buffer-local variables reference (:help notmuch-buffer-variables), and thread.lua module description - CHANGELOG: Note documentation additions
Add changelog entries describing the completion of the major refactoring that removed all Vimscript dependencies and migrated to pure Lua implementation with improved completion filtering.
Remove references to deleted plugin/notmuch.vim and autoload/notmuch.vim files. Reflect command definitions now in init.lua using vim.api.nvim_create_user_command. Update doc/notmuch.txt COMPLETION section to reference the new completion.lua Lua module instead of the old autoload function. Add completion.lua module documentation to the LUA MODULES section describing its purpose and exported functions.
Update TagAdd/TagRm/TagToggle commands in ftplugin files to use the new notmuch.completion.comp_tags Lua function instead of the deprecated notmuch#CompTags Vimscript autoload function. Use customlist completion type for proper handling of Lua table returns.
Introduce a `message_order` config option to control the order of messages displayed in the thread view. Users can choose between "newest-first" and "oldest-first" to suit their preference. When set to "newest-first", the thread view flattens and sorts messages by timestamp in descending order. Default behavior maintains the original hierarchical order.
Introduce a new attachment buffer for compose and reply workflows, modeled after oil.nvim. Users can add, remove, and paste file paths as attachments using intuitive keymaps and commands. The buffer supports direct file path entry, integration with oil.nvim for pasting/yanking, and validates attachments on save. Documentation and syntax highlighting for the new buffer are included. Also refactor attachment commands and sending logic to use the new buffer and improve user feedback.
|
@jugarpeupv I like this implementation a lot, it gives a best of both worlds for using a buffer approach that was done by @simonhughxyz as well as a command-driven one. However, I see that this PR contains changes from many different PR's and changes combined into one. Is it possible to clean it up into an atomic PR branch with just the attachment related changes? I haven't comprehensively reviewed it yet but I tried it a little bit and it seems good. |
|
@yousefakbar in theory in this branch i did that, started from your main branch, then committed the changes just to make this feature, but feel free to cherry pick well, now that i am reviewing it, it seems like in this PR i also incorporated the changes from the PR #38 and in that PR i also incorporated the changes to view html parts, because it is the current code state in which i am running notmuch locally sorry for the noise, i tried to be atomic ... please feel free to cherry pick i dont think i will be spending more time trying to be more atomic in this PRs since i am running notmuch from my fork locally anyway |
This is how attachment buffer looks like
@yousefakbar any thoughts on this?